import { fabric } from 'fabric';

import { getNoAnglePoints } from '@/pages/TemplateEditor/components/Editor/components/TemplateEffect/utils';

import { getRotatedPositionByCustomPoint } from './result';

// 只要圆心坐标发生变化，就会触发
export const handleRectTopMoving = (
  options: fabric.IEvent<MouseEvent>,
  cropLayer: fabric.Rect,
  imageInfo
): void => {
  options.e.stopPropagation();
  const { imageWidth, imageHeight, imageCenterTop, imageCenterLeft, angle } =
    imageInfo;

  // 摆正后的图片坐标原点
  const imagePoints = getNoAnglePoints({
    width: imageWidth,
    height: imageHeight,
    left: imageCenterLeft,
    top: imageCenterTop
  });

  // 计算当前裁剪框的宽度
  const currentWidth = cropLayer.getScaledWidth();
  const currentHeight = cropLayer.getScaledHeight();

  // 计算裁剪框原点坐标的拖动范围(裁剪范围)，限制裁剪框的大小不能超出被裁剪图片
  const topBound = imagePoints.leftTop.y + currentHeight / 2;
  const bottomBound = imagePoints.rightBottom.y - currentHeight / 2;
  const leftBound = imagePoints.leftTop.x + currentWidth / 2;
  const rightBound = imagePoints.rightBottom.x - currentWidth / 2;

  // 计算裁剪框摆正后的原点坐标，用于比对是否超出裁剪范围
  const { x: rectCenterLeftInBound, y: rectCenterTopInBound } =
    getRotatedPositionByCustomPoint(
      imagePoints.center,
      new fabric.Point(cropLayer.left, cropLayer.top),
      angle
    );

  // 计算是否超出拖动范围，没有超出则不需要进行限制
  const overBound =
    rectCenterLeftInBound < leftBound ||
    rectCenterLeftInBound > rightBound ||
    rectCenterTopInBound < topBound ||
    rectCenterTopInBound > bottomBound;

  if (!overBound) {
    return;
  }

  // 超出范围后，需要修正裁剪框坐标

  // 计算当前正确的摆正后裁剪框坐标
  const currentRectCenterTopInBound = Math.min(
    Math.max(rectCenterTopInBound, topBound),
    bottomBound
  );
  const currentRectCenterLeftInBound = Math.min(
    Math.max(rectCenterLeftInBound, leftBound),
    rightBound
  );

  // 根据摆正后坐标，计算当前裁剪框的正确坐标，并设置给裁剪框
  const { x: currentRectCenterLeft, y: currentRectCenterTop } =
    getRotatedPositionByCustomPoint(
      imagePoints.center,
      new fabric.Point(
        currentRectCenterLeftInBound,
        currentRectCenterTopInBound
      ),
      -angle
    );
  cropLayer.set({
    top: currentRectCenterTop,
    left: currentRectCenterLeft
  });
};

// 拖拽时触发
export const handleRectTopScaling = (
  options: fabric.IEvent<MouseEvent>,
  cropLayer: fabric.Rect,
  imageInfo,
  callback?: () => void
): void => {
  options.e.stopPropagation();
  const {
    imageWidth,
    imageHeight,
    scaleX,
    scaleY,
    imageCenterTop,
    imageCenterLeft,
    angle
  } = imageInfo;
  const maxScaleX = scaleX;
  const maxScaleY = scaleY;

  // 由于开始时裁剪框的大小与图片大小相同，限制scale，避免裁剪框的大小超过图片
  if (cropLayer.scaleX > maxScaleX) {
    cropLayer.set({
      scaleX: maxScaleX
    });
  }
  if (cropLayer.scaleY > maxScaleY) {
    cropLayer.set({
      scaleY: maxScaleY
    });
  }

  // 计算摆正后的图片坐标
  const imagePoints = getNoAnglePoints({
    width: imageWidth,
    height: imageHeight,
    left: imageCenterLeft,
    top: imageCenterTop
  });

  // 限制裁剪框的大小，不能大于被裁剪图片
  const currentWidth = Math.min(imageWidth, cropLayer.getScaledWidth());
  const currentHeight = Math.min(imageHeight, cropLayer.getScaledHeight());

  // 计算裁剪框原点坐标的拖动范围(裁剪范围)，限制裁剪框的大小不能超出被裁剪图片
  const topBound = imagePoints.leftTop.y + currentHeight / 2;
  const bottomBound = imagePoints.rightBottom.y - currentHeight / 2;
  const leftBound = imagePoints.leftTop.x + currentWidth / 2;
  const rightBound = imagePoints.rightBottom.x - currentWidth / 2;

  // 计算裁剪框摆正后的原点坐标，用于比对是否超出裁剪范围
  const { x: rectCenterLeftInBound, y: rectCenterTopInBound } =
    getRotatedPositionByCustomPoint(
      imagePoints.center,
      new fabric.Point(cropLayer.left, cropLayer.top),
      angle
    );

  // 当裁剪框宽度超出被裁剪图片时，限制裁剪框的大小
  if (rectCenterLeftInBound < leftBound || rectCenterLeftInBound > rightBound) {
    // 如果裁剪框没有变化，则复用已保存的值
    if (cropLayer.data.lockScaleX) {
      cropLayer.set({
        scaleX: cropLayer.data.lockScaleX
      });
    } else {
      let newWidth =
        rectCenterLeftInBound < leftBound
          ? // 如果裁剪框左侧超出，则裁剪框大小需要剪掉左侧超出的范围
            currentWidth / 2 - (imagePoints.leftTop.x - rectCenterLeftInBound)
          : // 如果裁剪框右侧超出，则裁剪框大小需要剪掉右侧超出的范围
            currentWidth / 2 -
            (rectCenterLeftInBound - imagePoints.rightBottom.x);
      const newScaleX = (cropLayer.scaleX * newWidth) / currentWidth;
      // 缩放到裁剪框大小
      cropLayer.set({
        scaleX: newScaleX,
        data: {
          ...cropLayer.data,
          lockScaleX: newScaleX
        }
      });
    }
  } else if (cropLayer.scaleX !== cropLayer.data.lockScaleX) {
    // 如果发生变化，则需要重新计算
    cropLayer.data.lockScaleX = null;
  }

  // 当裁剪的高度超出裁剪范围时，限制裁剪框的大小
  if (rectCenterTopInBound < topBound || rectCenterTopInBound > bottomBound) {
    if (cropLayer.data.lockScaleY) {
      cropLayer.set({
        scaleY: cropLayer.data.lockScaleY
      });
    } else {
      let newHeight =
        rectCenterTopInBound < topBound
          ? rectCenterTopInBound + currentHeight / 2 - imagePoints.leftTop.y
          : imagePoints.rightBottom.y -
            (rectCenterTopInBound - currentHeight / 2);
      const newScaleY = (cropLayer.scaleY * newHeight) / currentHeight;
      cropLayer.set({
        scaleY: newScaleY,
        data: {
          ...cropLayer.data,
          lockScaleY: newScaleY
        }
      });
    }
  } else if (cropLayer.scaleY !== cropLayer.data.lockScaleY) {
    cropLayer.data.lockScaleY = null;
  }

  callback && callback();

  handleRectTopMoving(options, cropLayer, imageInfo);
};
